package com.web.cms.pan.service;

import com.blue.core.dict.OperateType;
import com.blue.core.dict.State;
import com.blue.core.tree.TreeBuilder;
import com.blue.core.util.BeanUtil;
import com.blue.jdbc.JdbcDataSource;
import com.web.cms.pan.dao.FolderDao;
import com.web.cms.pan.dao.FolderFileDao;
import com.web.cms.pan.dao.OperatorLogDao;
import com.web.cms.pan.dao.UserInfoDao;
import com.web.cms.pan.exception.FolderException;
import com.web.cms.pan.model.Folder;
import com.web.cms.pan.model.OperatorLog;
import com.web.core.dict.PanExternalType;
import com.web.core.util.Const;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 目录业务层
 * 
 * @author 代码由 blue-code 框架生成
 * @since 1.0 2018年04月09日
 */
@Service("panFolderService")
@Transactional
@JdbcDataSource(Const.DS_CMS)
public class FolderService
{
	@Autowired
	private FolderDao folderDao;
	@Autowired
	private FolderFileDao folderFileDao;
	@Autowired
	private UserInfoDao userInfoDao;
	@Autowired
	private OperatorLogDao operatorLogDao;
	
	public FolderService()
	{
	}
	
	public Folder save(Folder folder)
	{
		if (folder.getUserId() != null)
		{
			userInfoDao.add(folder.getUserId());
		}
		if (folder.getId() == null)
		{
			folderDao.save(folder);
			operatorLogDao.add(folder.getUserId(), "创建目录：" + folder.getName(),
					folder.getId(), PanExternalType.DIRECTORY, OperateType.ADD);
		}
		else
		{
			folderDao.update(folder);
			operatorLogDao.add(folder.getUserId(), "更新目录：" + folder.getName(),
					folder.getId(), PanExternalType.DIRECTORY, OperateType.UPDATE);
		}
		Folder a = folderDao.get(folder.getId());
		return a;
	}
	
	public Folder get(Integer id)
	{
		Folder folder = folderDao.get(id);
		return folder;
	}
	
	public List<Folder> list(Folder folder)
	{
		if (folder.getUserId() != null)
		{
			userInfoDao.add(folder.getUserId());
		}

		List<Folder> list = folderDao.list(folder);
		return list;
	}

	public void state(Folder folder)
	{
		Folder f = folderDao.get(folder.getId());
		if (f == null)
			throw new FolderException("目录不存在：" + folder.getId());
		if (!f.getUserId().equals(folder.getUserId()))
			throw new FolderException("目录不与用户关联：" + folder.getUserId());

		Date now = (folder.getState() == State.DELETE ? new Date() : null);
		folderDao.updateObject(folder.getId(), "state", folder.getState().getIndex(), "deleteTime", now);
		operatorLogDao.add(folder.getUserId(), String.format("更新目录[%s]状态：%s", f.getName(), folder.getState().getName()),
				f.getId(), PanExternalType.DIRECTORY, OperateType.UPDATE);
	}
	
	public void delete(Integer userId, List<Integer> ids)
	{
		Date now = new Date();
		List<Folder> list = folderDao.listObject("userId", userId);
		Map<Integer, Folder> map = new HashMap<>();
		list.forEach(e -> map.put(e.getId(), e));
		Map<Integer, List<Folder>> parentMap = TreeBuilder.buildTree(list);

		Set<Integer> idSet = new HashSet<>();
		List<OperatorLog> logList = new ArrayList<>();
		int files = 0;
		int fileSize = 0;
		for (Integer id : ids)
		{
			Folder folder = map.get(id);
			if (folder == null)
				throw new FolderException("目录不存在或不与用户关联：" + id);

			idSet.add(id);
			logList.add(operatorLogDao.create(userId, "删除目录：" + folder.getName(),
					now, folder.getId(), PanExternalType.DIRECTORY, OperateType.DELETE));
			files += folder.getFiles().intValue();
			fileSize += folder.getFileSize().intValue();
			Queue<Integer> queue = new LinkedList<>();
			queue.offer(id);
			Integer parentId = null;
			while ((parentId = queue.poll()) != null)
			{
				List<Folder> tmpList = parentMap.get(parentId);
				if (tmpList == null || tmpList.isEmpty())
					continue;

				for (Folder f : tmpList)
				{
					queue.offer(f.getId());
					idSet.add(f.getId());
				}
			}
		}

		folderDao.deleteById(idSet);
		userInfoDao.inc(userId, "files", -files, "fileSize", -fileSize, "deleteFiles", files, "deleteFileSize", fileSize);
		operatorLogDao.saveList(logList);
	}

	public void move(int srcId, int destId)
	{
		folderDao.updateObject(srcId, "parentId", destId);
		Folder folder = folderDao.get(srcId);
		operatorLogDao.add(folder.getUserId(), "移动目录：" + folder.getName(),
				folder.getId(), PanExternalType.DIRECTORY, OperateType.UPDATE);
	}

	public void copy(Integer userId, int srcId, int destId)
	{
		List<Folder> list = folderDao.listObject("userId", userId);
		Map<Integer, List<Folder>> parentMap = TreeBuilder.buildTree(list);

		Folder folder = folderDao.get(srcId);
		Folder newFolder = BeanUtil.createBean(Folder.class, folder);
		newFolder.setParentId(destId);
		newFolder.setId(null);
		folderDao.save(newFolder); // 复制保存顶层目录

		Queue<Integer> queue = new LinkedList<>();
		Queue<Integer> parentQueue = new LinkedList<>();
		queue.offer(folder.getId());
		parentQueue.offer(newFolder.getId());
		Integer id = null;
		Integer parentId = null;
		while ((id = queue.poll()) != null && (parentId = parentQueue.poll()) != null)
		{
			List<Folder> tmpList = parentMap.get(id);
			if (tmpList == null || tmpList.isEmpty())
				continue;

			for (Folder f : tmpList)
			{
				Folder newF = BeanUtil.createBean(Folder.class, f);
				newF.setParentId(parentId);
				newF.setId(null);
				folderDao.save(newF);
				folderFileDao.copyByFolder(f.getId(), newF.getId());
				queue.offer(f.getId());
				parentQueue.offer(newF.getId());
			}
		}
		operatorLogDao.add(folder.getUserId(), "复制目录：" + folder.getName(),
				folder.getId(), PanExternalType.DIRECTORY, OperateType.UPDATE);
	}
	
}
